package com.party.web.biz.wechat;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.party.api.dto.wechat.requst.MenuButtonRequest;
import com.party.api.dto.wechat.requst.MenuRequest;
import com.party.api.dto.wechat.response.Response;
import com.party.api.service.wechat.IWechatService;
import com.party.common.constant.Constant;
import com.party.common.constant.WechatConstant;
import com.party.common.utils.LangUtils;
import com.party.common.utils.VerifyCodeUtils;
import com.party.core.exception.BusinessException;
import com.party.core.model.member.MemberExternalApp;
import com.party.core.model.member.MemberGroup;
import com.party.core.model.wechat.*;
import com.party.core.model.wechatPlatform.WechatOpenMember;
import com.party.core.service.member.IMemberExternalAppService;
import com.party.core.service.wechat.IWechatMaterialService;
import com.party.core.service.wechat.IWechatMenuService;
import com.party.core.service.wechat.IWechatMessageService;
import com.party.core.service.wechatPlatform.IWechatOpenMemberService;
import com.party.web.utils.RealmUtils;
import com.party.web.web.dto.input.wechat.WechatMenuInput;
import com.party.web.web.dto.input.wechat.WechatMenuInputWrapper;
import com.party.web.web.dto.output.wechat.WechatMenuOutput;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * 微信菜单业务接口
 * Created by wei.li
 *
 * @date 2017/8/29 0029
 * @time 17:18
 */
@Service
public class WechatMenuBizService {

    private static final Logger logger = LoggerFactory.getLogger(WechatMenuBizService.class);

    @Autowired
    private IWechatMenuService wechatMenuService;

    @Autowired
    private IWechatService wechatService;

    @Autowired
    private IWechatOpenMemberService wechatOpenMemberService;

    @Autowired
    private IWechatMessageService wechatMessageService;

    @Autowired
    private IWechatMaterialService wechatMaterialService;

    @Autowired
    private IMemberExternalAppService memberExternalAppService;

    /**
     * 父结构列表
     *
     * @param memberId 会员编号
     * @return 树列表
     */
    public List<WechatMenuOutput> treeList(String memberId) {
        WechatMenu wechatMenu = new WechatMenu();
        wechatMenu.setMemberId(memberId);
        List<WechatMenu> list = wechatMenuService.list(wechatMenu);
        List<WechatMenuOutput> unorderList = menuToTree(list, Constant.TOP_PARENT_ID);
        return transformOrderList(unorderList);
    }

    /**
     * 列表转树
     *
     * @param list     列表
     * @param parentId 父级编号
     * @return 树结构
     */
    public List<WechatMenuOutput> menuToTree(List<WechatMenu> list, String parentId) {
        List<WechatMenuOutput> wechatMenuOutputList = Lists.newArrayList();
        for (WechatMenu wechatMenu : list) {
            if (wechatMenu.getParentId().equals(parentId)) {
                WechatMenuOutput wechatMenuOutput = WechatMenuOutput.transform(wechatMenu);
                List<WechatMenuOutput> subList = menuToTree(list, wechatMenu.getId());
                wechatMenuOutput.setSubList(subList);
                //查找素材
                if(wechatMenu.getMediaId() != null){
                    WechatMaterial material = new WechatMaterial();
                    material.setMediaId(wechatMenu.getMediaId());
                    List<WechatMaterial> materialList = wechatMaterialService.list(material);
                    wechatMenuOutput.setMaterial(materialList);
                }
                wechatMenuOutputList.add(wechatMenuOutput);
            }
        }
        return wechatMenuOutputList;
    }

    /**
     * 根据sort字段重新排序列表
     *
     * @param unorderList 无序列表
     * @return 有序列表
     */
    public List<WechatMenuOutput> transformOrderList(List<WechatMenuOutput> unorderList) {
        Iterator<WechatMenuOutput> iterator = unorderList.iterator();
        WechatMenuOutput[] outputs = new WechatMenuOutput[unorderList.size()];
        while (iterator.hasNext()) {
            WechatMenuOutput mainMenu = iterator.next();
            int size = mainMenu.getSubList().size();
            WechatMenuOutput[] subList = new WechatMenuOutput[size];
            for (WechatMenuOutput subMenu : mainMenu.getSubList()) {
                subList[subMenu.getSort()] = subMenu;
            }
            mainMenu.setSubList(Arrays.asList(subList));
            outputs[mainMenu.getSort()] = mainMenu;
        }
        return Arrays.asList(outputs);
    }

    /**
     * 删除微信菜单
     *
     * @return
     */
    public boolean delAllMenu() {
        MemberGroup member = RealmUtils.getCurrentUser();
        checkNotNull(member, "当前用户为空");

        //WechatOpenMember wechatOpenMember = wechatOpenMemberService.findByMemberId(member.getId());
        MemberExternalApp memberExternalApp
                = memberExternalAppService.findByMemberIdAndDeployType(member.getId(), member.getDeployType());
        WechatOpenMember wechatOpenMember = wechatOpenMemberService.get(memberExternalApp.getExternalAccountId());
        if (null == wechatOpenMember) {
            throw new BusinessException("授权公众号不能为空");
        }
        boolean opFlag = wechatService.deleteMenu(wechatOpenMember.getAuthorizerAccessToken());
        if (opFlag) {
            String memberId = RealmUtils.getCurrentUser().getId();
            //清除用户当前菜单及其关联的消息
            WechatMenu wechatMenu = new WechatMenu();
            wechatMenu.setMemberId(memberId);
            List<WechatMenu> menuList = wechatMenuService.list(wechatMenu);
            for (WechatMenu menu : menuList) {
                wechatMessageService.delete(menu.getMessageId());
            }
            wechatMenuService.deleteByMemberId(memberId);
            return true;
        } else {
            return false;
        }
    }

    @Transactional(rollbackFor = BusinessException.class)
    public boolean create(List<WechatMenuInput> list, String memberId) {
        //生成关联的messageId
        for (WechatMenuInput input : list) {
            //如果是事件
            if (WechatMenuActionType.CLICK.getCode().equals(input.getActionType())) {
                WechatMessage wechatMessage = new WechatMessage();
                wechatMessage.setMemberId(memberId);
                if (WechatMessageReplyType.TEXT.getCode().equals(input.getMessageType())) {
                    wechatMessage.setType(WechatMessageType.EVENT_REPLY.getCode());
                    wechatMessage.setReplyType(WechatMessageReplyType.TEXT.getValue());
                    wechatMessage.setKey(VerifyCodeUtils.RandomString(4));
                    wechatMessage.setContent(input.getContent());
                }
                String messageId = wechatMessageService.insert(wechatMessage);
                input.setMessageId(messageId);
            }
        }

        //清除用户当前菜单、素材及其关联的消息
        WechatMenu wechatMenu = new WechatMenu();
        wechatMenu.setMemberId(memberId);
        List<WechatMenu> menuList = wechatMenuService.list(wechatMenu);
        for (WechatMenu menu : menuList) {
            wechatMessageService.delete(menu.getMessageId());
        }
        wechatMenuService.deleteByMemberId(memberId);
        wechatMaterialService.deleteByMemberId(memberId);
        //形成上下级关系后插入数据库
        int menuIndex = 0;
        for (WechatMenuInput input : list) {
            if ("0".equals(input.getParentId())) {
                String preParentId = input.getId();
                input.setId(null);  //清除临时ID
                input.setMemberId(memberId);
                input.setSort(menuIndex);
                menuIndex++;
                String parentId = wechatMenuService.insert(input);
                //插入素材
                this.insertMaterial(input,memberId);
                int subIndex = 0;
                for (WechatMenuInput sub : list) {
                    if (preParentId.equals(sub.getParentId())) {
                        sub.setParentId(parentId);
                        sub.setMemberId(memberId);
                        sub.setSort(subIndex);
                        subIndex++;
                        wechatMenuService.insert(sub);
                        //插入素材
                        this.insertMaterial(sub,memberId);
                    }
                }
            }
        }

        //上传至微信
        createMenu(list);
        return true;
    }


    /**
     * 创建微信菜单
     *
     * @param list 菜单列表
     * @return 是否成功（true/false）
     * @throws BusinessException
     */
    public boolean createMenu(List<WechatMenuInput> list) throws BusinessException {

        MemberGroup member = RealmUtils.getCurrentUser();
        checkNotNull(member, "当前用户为空");

        //WechatOpenMember wechatOpenMember = wechatOpenMemberService.findByMemberId(member.getId());
        MemberExternalApp memberExternalApp
                = memberExternalAppService.findByMemberIdAndDeployType(member.getId(), member.getDeployType());
        WechatOpenMember wechatOpenMember = wechatOpenMemberService.get(memberExternalApp.getExternalAccountId());
        if (null == wechatOpenMember) {
            throw new BusinessException("授权公众号不能为空");
        }

        MenuRequest menuRequest = new MenuRequest();
        List<MenuButtonRequest> menuButtonRequestList = menuToRequest(list, Constant.TOP_PARENT_ID);
        menuRequest.setButton(menuButtonRequestList);
        Response menuResponse = wechatService.createMenu(menuRequest, wechatOpenMember.getAuthorizerAccessToken());
        logger.debug("申请的菜单：{}", JSONObject.toJSONString(menuRequest).toString());
        if (!menuResponse.getErrcode().equals(WechatConstant.SUCCESS_CODE)) {
            throw new BusinessException(Integer.valueOf(menuResponse.getErrcode()), menuResponse.getErrmsg());
        }
        return true;
    }


    /**
     * 微信菜单保存
     *
     * @param list     列表
     * @param memberId 会员编号
     */
    @Transactional
    public void save(List<WechatMenuInput> list, String memberId) {
        for (WechatMenuInput input : list) {

            //如果是事件
            if (WechatMenuActionType.CLICK.getCode().equals(input.getActionType())) {
                WechatMessage wechatMessage = new WechatMessage();
                wechatMessage.setMemberId(memberId);
                if (WechatMessageReplyType.TEXT.getCode().equals(input.getMessageType())) {
                    wechatMessage.setType(WechatMessageType.EVENT_REPLY.getCode());
                    wechatMessage.setReplyType(WechatMessageReplyType.TEXT.getValue());
                    wechatMessage.setKey(VerifyCodeUtils.RandomString(4));
                    wechatMessage.setContent(input.getContent());
                } else if (WechatMessageReplyType.NEWS.getCode().equals(input.getMessageType())) {
                    wechatMessage.setType(WechatMessageType.EVENT_REPLY.getCode());
                    wechatMessage.setReplyType(WechatMessageReplyType.NEWS.getValue());
                    wechatMessage.setKey(VerifyCodeUtils.RandomString(4));
                    String content = JSONObject.toJSONString(input.getWechatItemInputList());
                    wechatMessage.setContent(content);
                    input.setContent(content);
                    input.setMessageId(wechatMessage.getId());
                }
                wechatMessageService.insert(wechatMessage);
            }
        }

        List<WechatMenu> wechatMenuList = LangUtils.transform(list, new Function<WechatMenuInput, WechatMenu>() {
            @Override
            public WechatMenu apply(WechatMenuInput wechatMenuInput) {
                return wechatMenuInput;
            }
        });
        wechatMenuService.batchInsert(wechatMenuList, memberId);
    }


    /**
     * 转换成请求格式
     *
     * @param list     列表
     * @param parentId 父级编号
     * @return 请求列表
     */
    private List<MenuButtonRequest> menuToRequest(List<WechatMenuInput> list, String parentId) {
        List<MenuButtonRequest> buttonList = Lists.newArrayList();
        for (WechatMenu wechatMenu : list) {
            if (parentId.equals(wechatMenu.getParentId())) {
                MenuButtonRequest menuButtonRequest = transform(wechatMenu);
                List<MenuButtonRequest> subList = menuToRequest(list, wechatMenu.getId());
                menuButtonRequest.setButtonRequestList(subList);
                buttonList.add(menuButtonRequest);
            }
        }
        return CollectionUtils.isEmpty(buttonList) ? null : buttonList;
    }


    /**
     * 转换请求参数
     *
     * @param wechatMenu 微信菜单
     * @return 请求参数
     */
    private MenuButtonRequest transform(WechatMenu wechatMenu) {
        MenuButtonRequest menuButtonRequest = new MenuButtonRequest();
        menuButtonRequest.setName(wechatMenu.getName());
        if (null != wechatMenu.getActionType()) {
            //消息触发
            if (wechatMenu.getActionType().equals(WechatMenuActionType.CLICK.getCode())) {
                menuButtonRequest.setType(WechatMenuActionType.CLICK.getValue());
                WechatMessage wechatMessage = wechatMessageService.get(wechatMenu.getMessageId());
                if (null != wechatMessage) {
                    menuButtonRequest.setKey(wechatMessage.getKey());
                }
            }
            //网页链接
            else if (wechatMenu.getActionType().equals(WechatMenuActionType.VIEW.getCode())) {
                menuButtonRequest.setType(WechatMenuActionType.VIEW.getValue());
                menuButtonRequest.setUrl(wechatMenu.getUrl());
            }
            //素材类型
            else if (wechatMenu.getActionType().equals(WechatMenuActionType.IMAGE.getCode())
                    || wechatMenu.getActionType().equals(WechatMenuActionType.NEWS.getCode())) {
                menuButtonRequest.setType("media_id");
                menuButtonRequest.setMediaId(wechatMenu.getMediaId());
            }
        }
        return menuButtonRequest;
    }

    private void insertMaterial(WechatMenuInput input,String memberId){
        if(input.getMaterial() == null){
            return;
        }
        List<WechatMaterial> list = WechatMenuInputWrapper.transformMaterial(input.getMaterial(),input.getMediaId(),memberId);
        wechatMaterialService.batchInsert(list);
    }
}
